一次vscode copilot插件fork bomb引起的服务器DoS
Transformed from Logseq page
一次vscode copilot插件fork bomb引起的服务器DoS
-
摘要#
2026 年 5 月 10 日凌晨,组里一台 CentOS 服务器突发响应极慢,
top几乎卡死。当晚因ps等统计命令同样缓慢,未能定位原因。次日早晨发现用户yicheng名下涌现 8 万余个node/copilot/sh进程,且pkill -9无法抑制。尝试loginctl terminate-user无效,最终通过 cgroup 限制用户进程数(pids.max)阻断新进程创建,存量进程以每秒约百个的速度缓慢下降。元凶指向 VS Code SSH Server 配合 Copilot 插件的失控行为。本次故障暴露了 Linux 内核在进程、文件描述符等子系统间缺乏有效隔离的设计缺陷,单一用户的 fork 炸弹或文件句柄耗尽即可引发全局 DoS。
-
1. 故障现象(2026-05-10 凌晨 1 时)#
-
用户执行
top响应极慢,几乎卡死。 -
top摘要显示:
Tasks: 165984 total, 62 zombie
%Cpu(s): 2.5 us, 3.6 sy, 93.8 id
MiB Mem: 1031898+ total, 84783 free, 566539 used, 380576 buff/cache -
当晚尝试使用
ps配合管道进行复杂统计(如按父进程聚合)时,命令直接卡住无法返回结果。 -
也尝试排查 Docker 容器、检查文件句柄等,均无明显发现。
-
-
2. 第二次排查(次日上午)#
重启终端后,基础
ps命令得以执行。按用户统计进程:
bashps -u yicheng -o comm= | sort | uniq -c | sort -nr | head -10输出:
plaintext73266 node 73259 copilot 73171 sh 69 fish 22 bash 7 docker ...结论:用户
yicheng下存在海量node、copilot、sh进程,且数量持续增长。 -
3. 初步清理尝试(均失败)#
-
执行
sudo pkill -9 -u yicheng,无明显效果。 -
再次统计,进程数反而从 7.7 万涨至 8.3 万:
plaintext83241 node 83234 copilot 83146 sh -
观察到个别 PID 较小的进程即使
kill -9也无法杀死,状态显示为S1(可中断睡眠但无法响应信号)。 -
尝试
sudo loginctl terminate-user yicheng——无效,进程数仍在增长。分析:进程创建速度超过杀死速度,仅靠发信号已无法遏制。
-
-
4. 最终阻断:cgroup 限制用户进程数#
-
使用 cgroup v2 限制用户
yicheng的最大进程数:
bash# 获取用户 UID id -u yicheng # 假设 1001 # 设置 pids.max = 500 echo 500 > /sys/fs/cgroup/user.slice/user-1001.slice/pids.max-
写入后,新进程立即无法创建(任何
fork返回“资源暂时不可用”)。 -
pkill/killall后,存量进程开始缓慢退出,下降速度约为每秒 100~200 个。
-
但不知是kill的作用还是进程本身超时等主动退出
-
-
-
设置 cgroup 限制后,我自己(yicheng 用户)反而无法登录了。
-
我是通过docker提权到root进行的诊断修复
-
设置资源限制时必须预留逃生通道,避免将自己锁在门外 在通过 cgroup 限制用户
pids.max时,若设置的值小于用户当前已有的进程数,任何新建进程(包括登录 shell、ssh 会话、sudo子进程)都会被立即拒绝,导致该用户无法再登录系统。 实施动态限制前,应先用ps -u <user> | wc -l评估当前进程数,设置一个合理上限
-
-
-
5. 恢复情况#
-
截至发稿,进程数仍在上万级别,以约百个/秒的速度下降。
-
系统整体负载有所缓解,
top响应恢复至可用状态。 -
完全清除所有失控进程尚需时间,服务器暂保持运行观察。
-
-
6. 根因分析(已确认)#
-
通过检查用户
yicheng的进程命令行及工作环境,确定失控进程来源于 VS Code SSH Server(即code-server的远程开发会话)及其驱动的 Copilot 插件。 -
具体机制推测:
-
VS Code SSH Server 会在用户登录时启动多个
node进程,其中包括扩展宿主(Extension Host)。 -
Copilot 插件在后台持续分析代码,可能因工作区过大或内部 bug 导致扩展宿主反复崩溃。
-
每次崩溃后,VS Code Server 的父进程会重新拉起新的扩展宿主,但旧的
node进程并未被正确回收(残留为S状态)。 -
由于崩溃频率极高,新进程创建速度远超系统清理速度,最终积累至数万级别。
-
-
为什么
pkill和loginctl无效?-
pkill -9虽然发送信号,但新进程创建速度更快,表现为“杀不完”。 -
loginctl terminate-user依赖 systemd 的用户会话管理器,而在进程表极度膨胀时,管理器自身也难以遍历并杀死全部进程树。
-
-
-
7. 经验教训#
-
极端进程数下,系统瓶颈不在 CPU/内存,而在内核管理开销 本次故障中,系统总进程数超过 16 万,但 CPU 空闲仍有 93.8%,内存也未耗尽。然而
top、ps、pstree等基础命令几乎卡死,因为管理工具需要遍历/proc下数十万个目录,而内核调度器、进程回收等机制在海量进程(即便多数处于S状态)下也会产生巨大的元数据开销。这表明 Linux 在面对超大规模进程数时,存在“非资源耗尽型”的性能悬崖——系统并非因 CPU/内存不足而不可用,而是因内核态操作本身的复杂度导致响应瘫痪。 -
进程创建速度超过杀死速度时,必须先阻断源头
pkill -9和loginctl terminate-user在进程爆炸且持续快速重生时无效。只有通过 cgroup 限制pids.max从内核层面阻止新进程创建,才能遏制恶化。这提示管理员应默认启用用户级进程数限制(如UserTasksMax)。 -
Linux 资源隔离仍不够精细,单点故障易引发全局 DoS 一个用户的失控进程(即便非恶意)即可耗尽全局
pid_max或file-max,导致其他用户甚至root的基础操作受阻。虽然 cgroup 提供了事后限制的手段,但默认配置下缺乏有效的预防隔离。建议在多用户环境中主动为每个用户或服务设置进程数、文件句柄数的上限。 -
管理工具在极端负载下的脆弱性
top、ps等工具依赖遍历/proc,当进程数超过 10 万时,这些命令自身可能阻塞数分钟甚至超时。此时应依赖更底层的接口(如直接读取cgroup统计)或提前部署监控告警,避免陷入“想排查但工具不可用”的窘境。
-
-
附录:关键命令备忘#
-
bash# 统计用户进程数按命令分组 ps -u yicheng -o comm= | sort | uniq -c | sort -nr | head # 限制用户 cgroup 进程数(cgroup v2) echo 500 > /sys/fs/cgroup/user.slice/user-$(id -u yicheng).slice/pids.max # 查看进程状态分布 ps aux | awk '{print $8}' | sort | uniq -c | sort -nr # 永久限制用户进程数(/etc/systemd/logind.conf) UserTasksMax=1000最后:服务器尚未完全恢复,但已遏制恶化。根本修复需等待 VS Code SSH Server 或 Copilot 插件更新,同时加强系统资源限制策略。
-